package io.kiki.sba.registry.store.jdbc.repository.impl;


import io.kiki.sba.registry.common.model.appmeta.InterfaceMapping;
import io.kiki.sba.registry.common.model.store.StringInterner;
import io.kiki.sba.registry.store.jdbc.domain.InterfaceAppsIndexDomain;
import io.kiki.sba.registry.store.jdbc.informer.DbEntryContainer;
import io.kiki.sba.registry.util.TimestampUtil;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class InterfaceAppsIndexContainer implements DbEntryContainer<InterfaceAppsIndexDomain> {

    // <dataInfoId, <dataCenter, InterfaceMapping>>
    private final Map<String, Map<String, InterfaceMapping>> multiData = new ConcurrentHashMap<>();

    private void addEntry(InterfaceAppsIndexDomain entry) {

        String interfaceName = StringInterner.intern(entry.getInterfaceName());
        String dataCenter = StringInterner.intern(entry.getDataCenter());
        String appName = StringInterner.intern(entry.getAppName());
        long nanoTime = TimestampUtil.getNanosLong(entry.getGmtCreate());

        Map<String, InterfaceMapping> data = multiData.computeIfAbsent(interfaceName, k -> new ConcurrentHashMap<>());

        InterfaceMapping mapping = data.computeIfAbsent(dataCenter, k -> new InterfaceMapping(nanoTime, appName));
        data.put(dataCenter, mapping.addApp(nanoTime, appName));
    }

    private void removeEntry(InterfaceAppsIndexDomain entry) {

        String interfaceName = StringInterner.intern(entry.getInterfaceName());
        String dataCenter = StringInterner.intern(entry.getDataCenter());
        String appName = StringInterner.intern(entry.getAppName());
        long nanoTime = TimestampUtil.getNanosLong(entry.getGmtCreate());

        Map<String, InterfaceMapping> data = multiData.computeIfAbsent(interfaceName, k -> new ConcurrentHashMap<>());

        InterfaceMapping mapping = data.computeIfAbsent(dataCenter, k -> new InterfaceMapping(nanoTime));
        data.put(dataCenter, mapping.removeApp(nanoTime, appName));
    }

    public boolean containsName(String dataCenter, String interfaceName, String appName) {
        Map<String, InterfaceMapping> data = multiData.get(interfaceName);
        if (CollectionUtils.isEmpty(data)) {
            return false;
        }

        InterfaceMapping mapping = data.get(dataCenter);
        if (mapping == null) {
            return false;
        }
        return mapping.getApps().contains(appName);
    }

    public Map<String, InterfaceMapping> getAppMapping(String interfaceName) {
        if (CollectionUtils.isEmpty(multiData.get(interfaceName))) {
            return Collections.EMPTY_MAP;
        }
        return new HashMap<>(multiData.get(interfaceName));
    }

    public Set<String> interfaces() {
        return multiData.keySet();
    }

    public Map<String, Map<String, InterfaceMapping>> allServiceMapping() {
        return new HashMap<>(multiData);
    }

    @Override
    public synchronized void onEntry(InterfaceAppsIndexDomain entry) {
        if (entry.isReference()) {
            addEntry(entry);
        } else {
            removeEntry(entry);
        }
    }
}
